#Requires -Version 7.0
<#
.SYNOPSIS
script for azure-sdk-for-net CI check in Unified Pipeline

.DESCRIPTION
Automatically generate and verify the SDK for both management-plane and data-plane.
Unified pipeline will run this script.

.PARAMETER inputJsonFile
Path to the input json file to contain all the input paramters.

.PARAMETER outputJsonFile
Path to the script output json file.

.EXAMPLE
Run script with default parameters.

Invoke-GenerateAndBuildV2.ps1 -inputJsonFile <inputJsonFile> -outputJsonFile <outputJsonFile>

please refer to eng/scripts/automation/unified-pipeline-test.md for more test scenaros and the sample inputJson and outputJson.

#>
param (
  [string]$inputJsonFile,
  [string]$outputJsonFile
)

. (Join-Path $PSScriptRoot ".." "common" "scripts" "Helpers" PSModule-Helpers.ps1)
. (Join-Path $PSScriptRoot automation GenerateAndBuildLib.ps1)

$inputJson = Get-Content $inputJsonFile | Out-String | ConvertFrom-Json
$swaggerDir = $inputJson.specFolder
if($swaggerDir) {
    $swaggerDir = Resolve-Path $swaggerDir
}
$swaggerDir = $swaggerDir -replace "\\", "/"
[string[]] $inputFilePaths = $inputJson.changedFiles;
$readmeFiles = $inputJson.relatedReadmeMdFiles
$commitid = $inputJson.headSha
$repoHttpsUrl = $inputJson.repoHttpsUrl
$downloadUrlPrefix = $inputJson.installInstructionInput.downloadUrlPrefix
$autorestConfig = $inputJson.autorestConfig
$relatedTypeSpecProjectFolder = $inputJson.relatedTypeSpecProjectFolder
$apiVersion = $inputJson.apiVersion
$sdkReleaseType = $inputJson.sdkReleaseType

function Update-PackageVersionSuffix {
    param(
        [string]$csprojPath,
        [string]$sdkReleaseType
    )
    
    if (-not $sdkReleaseType) {
        Write-Host "No sdkReleaseType provided, skipping version suffix update"
        return
    }
    
    if (-not (Test-Path $csprojPath)) {
        Write-Warning "csproj file not found at $csprojPath"
        return
    }
    
    Write-Host "Updating package version suffix based on sdkReleaseType: $sdkReleaseType"
    
    # Load the csproj file as XML
    [xml]$csproj = Get-Content $csprojPath
    
    # Find the PropertyGroup that contains the Version element
    $versionElement = $null
    foreach ($propertyGroup in $csproj.Project.PropertyGroup) {
        if ($propertyGroup.Version) {
            $versionElement = $propertyGroup.SelectSingleNode("Version")
            break
        }
    }
    
    if (-not $versionElement) {
        Write-Warning "No Version element found in $csprojPath"
        return
    }
    
    $currentVersion = $versionElement.InnerText
    Write-Host "Current version: $currentVersion"
    
    $newVersion = $currentVersion
    $versionChanged = $false
    
    if ($sdkReleaseType -eq "beta") {
        # If release type is beta, ensure version has beta suffix
        if ($currentVersion -notmatch '-beta\.\d+$') {
            # Version doesn't have beta suffix, add it
            $newVersion = "$currentVersion-beta.1"
            Write-Host "Adding beta suffix. New version: $newVersion"
            $versionChanged = $true
        } else {
            Write-Host "Version already has beta suffix, no change needed"
        }
    } elseif ($sdkReleaseType -eq "stable") {
        # If release type is stable, remove beta suffix if present
        if ($currentVersion -match '^(.+)-beta\.\d+$') {
            $newVersion = $matches[1]
            Write-Host "Removing beta suffix. New version: $newVersion"
            $versionChanged = $true
        } else {
            Write-Host "Version is already stable (no beta suffix), no change needed"
        }
    } else {
        Write-Warning "Unknown sdkReleaseType: $sdkReleaseType. Expected 'beta' or 'stable'"
        return
    }
    
    # Update and save if version changed
    if ($versionChanged) {
        $versionElement.InnerText = $newVersion
        $csproj.Save($csprojPath)
        Write-Host "Successfully updated version to $newVersion in $csprojPath"
    }
}

$autorestConfigYaml = ""
if ($autorestConfig) {
    $autorestConfig | Set-Content "config.md"
    $autorestConfigYaml = Get-Content -Path ./config.md
    $range = ($autorestConfigYaml | Select-String -Pattern '```').LineNumber
    if ( $range.count -gt 1) {
        $startNum = $range[0];
        $lines = $range[1] - $range[0] - 1
        $autorestConfigYaml = ($autorestConfigYaml | Select -Skip $startNum | Select -First $lines) |Out-String
    }

    Install-ModuleIfNotInstalled "powershell-yaml" "0.4.1" | Import-Module
    $yml = ConvertFrom-YAML $autorestConfigYaml
    $requires = $yml["require"]
    if ($requires.Count -gt 0) {
        $readmeFiles = $requires
    }
}

$generatedSDKPackages = New-Object 'Collections.Generic.List[System.Object]'

$sdkPath =  (Join-Path $PSScriptRoot .. ..)
$sdkPath = Resolve-Path $sdkPath
$sdkPath = $sdkPath -replace "\\", "/"
for ($i = 0; $i -le $readmeFiles.Count - 1; $i++) {
    $readmeFile = $readmeFiles[$i] -replace "\\", "/"
    $readme = ""
    if ( $swaggerDir) {
        $readme = (Join-Path $swaggerDir $readmeFile)
    } elseif ( $commitid) {
        if ($repoHttpsUrl) {
            $readme = "$repoHttpsUrl/blob/$commitid/$readmeFile"
        } else {
            $readme = "https://github.com/$org/azure-rest-api-specs/blob/$commitid/$readmeFile"
        }
    } else {
        throw "[ERROR] Neither 'specFolder' nor 'headSha' is provided for `$readmeFile`. Please report this issue through https://aka.ms/azsdk/support/specreview-channel and include this pull request."
    }

    if ($autorestConfigYaml) {
        $readmeFiles[$i] = $readme
        $autorestConfigYaml = ConvertTo-YAML $yml
    }
    Invoke-GenerateAndBuildSDK -readmeAbsolutePath $readme -sdkRootPath $sdkPath -autorestConfigYaml "$autorestConfigYaml" -downloadUrlPrefix "$downloadUrlPrefix" -generatedSDKPackages $generatedSDKPackages
    $generatedSDKPackages[$generatedSDKPackages.Count - 1]['readmeMd'] = @($readmeFile)
}

#update services without readme.md
$serviceWithReadme = @()
foreach( $readme in $readmeFiles) {
    $service, $serviceType = Get-ResourceProviderFromReadme $readme
    $serviceWithReadme += @($service)
}
$inputFileToGen = @()
foreach( $file in $inputFilePaths) {
    if ( $file -match "specification/(?<specName>.*)/data-plane|resource-manager" ) {
        if (!$serviceWithReadme.Contains($matches["specName"])) {
            $inputFileToGen += @($file)
        }
    }

}

if ($inputFileToGen) {
    UpdateExistingSDKByInputFiles -inputFilePaths $inputFileToGen -sdkRootPath $sdkPath -headSha $commitid -repoHttpsUrl $repoHttpsUrl -downloadUrlPrefix "$downloadUrlPrefix" -generatedSDKPackages $generatedSDKPackages
}

$exitCode = 0
# generate sdk from typespec file
if ($relatedTypeSpecProjectFolder) {
    foreach ($typespecRelativeFolder in $relatedTypeSpecProjectFolder) {
        $typespecFolder = Resolve-Path (Join-Path $swaggerDir $typespecRelativeFolder)
        $tspConfigFile = Resolve-Path (Join-Path $typespecFolder "tspconfig.yaml")
        $sdkProjectFolder = GetSDKProjectFolder -typespecConfigurationFile $tspConfigFile -sdkRepoRoot $sdkPath
        $sdkAutorestConfigFile = Join-path $sdkProjectFolder "src" "autorest.md"
        if (Test-Path -Path $sdkAutorestConfigFile) {
            Write-Host "remove $sdkAutorestConfigFile for sdk from typespec."
            Remove-Item -Path $sdkAutorestConfigFile
        }
        $serviceType = "data-plane"
        $packageName = Split-Path $sdkProjectFolder -Leaf
        if ($packageName.StartsWith("Azure.ResourceManager.")) {
            $serviceType = "resource-manager"
        }
        $repo = $repoHttpsUrl -replace "https://github.com/", ""
        Write-host "Start to call tsp-client to generate package:$packageName"
        
        # Install tsp-client dependencies from eng/common/tsp-client
        $tspClientDir = Resolve-Path (Join-Path $PSScriptRoot "../common/tsp-client")
        Push-Location $tspClientDir
        try {
            Write-Host "Installing tsp-client dependencies from $tspClientDir"
            npm ci
            if ($LASTEXITCODE) {
                Write-Error "Failed to install tsp-client dependencies"
                exit $LASTEXITCODE
            }
        }
        finally {
            Pop-Location
        }
        
        # Use tsp-client from pinned version by passing --prefix to use tsp-client from that directory
        $tspclientCommand = "npm exec --prefix $tspClientDir --no -- tsp-client init --update-if-exists --tsp-config $tspConfigFile --repo $repo --commit $commitid"
        if ($swaggerDir) {
            $tspclientCommand += " --local-spec-repo $typespecFolder"
        }
        if ($apiVersion) {
            # Validate apiVersion format to prevent command injection - allow alphanumeric, dots, and dashes
            if ($apiVersion -match '^[a-zA-Z0-9.-]+$') {
                $tspclientCommand += " --emitter-options `"api-version=$apiVersion`""
            } else {
                Write-Warning "apiVersion '$apiVersion' contains invalid characters and will be skipped. Only alphanumeric characters, dots, and dashes are allowed."
            }
        }
        Write-Host $tspclientCommand
        Invoke-Expression $tspclientCommand
        
        if ($LASTEXITCODE) {
          # If Process script call fails, then return with failure to CI and don't need to call GeneratePackage
          Write-Host "[ERROR] Failed to generate typespec project:$typespecFolder. Exit code: $LASTEXITCODE. Please review the detail errors for potential fixes. If the issue persists, contact the DotNet language support channel at $DotNetSupportChannelLink and include this spec pull request."
          $generatedSDKPackages.Add(@{
            result = "failed";
            path=@("");
          })
          $exitCode = $LASTEXITCODE
        } else {
            # Update package version suffix based on sdkReleaseType
            if ($sdkReleaseType) {
                $csprojPath = Join-Path $sdkProjectFolder "src" "$packageName.csproj"
                Update-PackageVersionSuffix -csprojPath $csprojPath -sdkReleaseType $sdkReleaseType
            }
            
            $relativeSdkPath = Resolve-Path $sdkProjectFolder -Relative
            GeneratePackage `
            -projectFolder $sdkProjectFolder `
            -sdkRootPath $sdkPath `
            -path $relativeSdkPath `
            -downloadUrlPrefix $downloadUrlPrefix `
            -serviceType $serviceType `
            -skipGenerate `
            -generatedSDKPackages $generatedSDKPackages `
            -specRepoRoot $swaggerDir
        }
        $generatedSDKPackages[$generatedSDKPackages.Count - 1]['typespecProject'] = @($typespecRelativeFolder)
    }
}
$outputJson = [PSCustomObject]@{
    packages = $generatedSDKPackages
}
$outputJson | ConvertTo-Json -depth 100 | Out-File $outputJsonFile
exit $exitCode
